/*******************************************************************************
 * Copyright 2007, 2009 InnovaSoft SA http://www.innovasoft.biz/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
 
package biz.innovasoft.nodb;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import net.sf.cglib.proxy.Proxy;

import org.prevayler.Prevayler;
import org.prevayler.PrevaylerFactory;

import biz.innovasoft.nodb.impl.GenericRepository;
import biz.innovasoft.nodb.interceptors.BaseInterceptor;

public class RepositoryProxy implements Runnable {

	private RepositoryCore core;
	private Prevayler prevayler;
	private GenericRepository prevSystem;
	private Object proxy;
	private final RepositoryConfiguration config;
	private Timer snapshotTimer;
	
	public RepositoryProxy (RepositoryConfiguration config) {
		this.config = config;
		try {
			initialize ();
		} catch (Exception e) {
			throw new RepositoryException("Can't open Repository at location: " + config.getRepositoryPath() , e);
		}
		this.proxy = newInstance();
	}
	
	private void initialize () throws Exception {
		PrevaylerFactory factory = new PrevaylerFactory ();
		factory.configureJournalFileAgeThreshold(config.getJournalFileAge());
		factory.configureJournalFileSizeThreshold(config.getJournalFileSize());
		factory.configurePrevalenceDirectory(config.getRepositoryPath());
		factory.configureTransactionFiltering(config.isPrevaylerTransactionFiltering());
		factory.configurePrevalentSystem(new GenericRepository(config.isCompressed()));
					
		this.prevayler = factory.create();
		this.prevSystem = (GenericRepository)prevayler.prevalentSystem();
		prevSystem.initialize(config);
		
		if (config.isReindexAtStartup()) {
			prevSystem.reindex();
		}
		
		if (config.isAutomaticSnapshots()) {
			snapshotTimer = new Timer(true);
			snapshotTimer.scheduleAtFixedRate(new SnapshotTask(prevayler), 
					TimeUnit.MINUTES.toMillis(config.getAutomaticSnapshotsTime()), 
					TimeUnit.MINUTES.toMillis(config.getAutomaticSnapshotsTime()));
		}
	}

	public Object getProxy() {
		return proxy;
	}
	
	protected RepositoryCore getCore () {
		return core;
	}

	protected Object newInstance() {
		BaseInterceptor interceptor = new BaseInterceptor ();
		Object proxy = Proxy.newProxyInstance(Repository.class.getClassLoader(),
				new Class[] { Repository.class }, interceptor);
		core = new RepositoryCore(prevayler, (Repository)proxy, prevSystem, config);
		interceptor.setRepositoryCore(core);
		return proxy;
	}
	
	private static class SnapshotTask extends TimerTask {

		private Prevayler _prevayler;
		
		public SnapshotTask(Prevayler prevayler) {
			this._prevayler = prevayler;
		}
		
		public void run() {
			try {
				_prevayler.takeSnapshot();
			} catch (Exception e) {
				throw new RepositoryException(
						"Error taking snapshot.", e);
			}
			
		}
		
	}

	@Override
	public void run() {
		try {
			initialize ();
		} catch (Exception e) {
			throw new RepositoryException("Can't open Repository at location: " + config.getRepositoryPath() , e);
		}
	}

}
